sitepoint.com의 Node.js 관련 Article 번역
원문 sitepoint.com의 Accessing the File System in Node.js
오역 주의 오역을 발견하시면 꼭 알려주세요~~ :-)
지난 수년동안 JavaScript는 파일 시스템에 대한 접근이 아주 제한적이었다. 물론 JavaScript는 그동안 대부분이 브라우저에서만 동작을 했다. 웹 스크립팅 언어로 파일 시스템에 접근하는 것은 보안에 대한 큰 위험요소라고 간주되었다. 프론트 엔드 개발자들은 쿠키, 웹스토리지, 엑티브엑스나 기타 다른 기술들을 사용할 수 밖에 없었다. HTML5가 파일 시스템 API에 대해 다루었지만 크롬 이외에는 대부분 여전히 지원되지 않는다. Node.js의 출현으로 JavaScript는 적합한 서버측 언어로써 발판을 확보하기 시작했다. 서버에서의 파일 시스템 접근은 일반적인 일로 API에 대해서 훨씬 덜 고민하게 한다.
기본적으로 Node.js 설치 시 파일 시스템 모듈인 fs도 같이 설치된다. fs
모듈은 대부분 단순하게 표준 파일 작업에 대한 래퍼를 제공한다. 다음의 예제에서는 파일의 내용을 메모리로 읽기 위해 파일 시스템 모듈을 사용한다. 우선 1 라인에서 파일 시스템 모듈을 임포트 하고 3 라인에서는 exist()
함수가 “foo.txt”
파일의 존재 여부를 확인한다. exists()
의 콜백 함수는 파일의 존재 여부를 명시한 불리언 값을 인자로 받는다. 그 다음의 stat()
함수는 파일의 길이를 바이트 단위로 확인하기 위해 사용된다. 이 정보가 중요한데 그 이유는 그것으로 인해 우리가 읽어야 할 데이터양을 알수 있기 때문이다.
다음으로 open()
을 사용해서 파일을 여는데 여기에서 r
인자는 파일이 읽기 전용으로 열린다는 것을 의미한다. open()
의 콜백 함수는 새로 연 파일을 접근하기 위한 파일 디스크립터인 fd
를 제공한다. 콜백 함수 안에서 우리는 파일의 내용을 담아둘 버퍼를 정의한다. 버퍼의 크기가 stats.size
에 저장되어 있는 파일의 크기로 초기화 됐다는 것을 주목해라. 그 다음, 파일은 read()
함수를 사용해서 버퍼로 읽어 들인다. 버퍼는 이제 파일로부터 읽어들인 로우 데이터를 포함하고 있다. 데이터를 표시하기 위해서는 먼저 UTF-8로 인코딩된 스트링으로 변환을 해야 한다. 마지막으로 파일 내용을 콘솔에 출력하고 파일을 닫는다.
var fs = require("fs");
var fileName = "foo.txt";
fs.exists(fileName, function(exists) {
if (exists) {
fs.stat(fileName, function(error, stats) {
fs.open(fileName, "r", function(error, fd) {
var buffer = new Buffer(stats.size);
fs.read(fd, buffer, 0, buffer.length, null, function(error, bytesRead, buffer) {
var data = buffer.toString("utf8", 0, buffer.length);
console.log(data);
fs.close(fd);
});
});
});
}
});
문서들을 살펴볼 때 많은 함수들의 이름 끝이 Sync
로 되어 있는 것을 주의해야 한다. 이것들은 동기화 함수를 나타낸다(Node.js의 콜백 기반에서는 다소 드문...). 동기화 함수는 편의성을 위해 제공한다. 예를 들어, Node.js로 작성된 간단한 배치 스크립트는 성능 최적화에 대해 고민할 필요는 없다. 또한, 동기화 함수는 프로그램이 초기화되는 동안 특정 파일들을 로딩하는 데 유용하다. 하지만, 실제 운영중인 서버 애플리케이션에서의 동기화 함수는 Node의 싱글 스레드 실행으로 인한 지연에 의해 심각한 성능 저하의 가능성이 있다.
다음 예제들은 동기적 또는 비동기적으로 어떻게 파일을 메모리로 읽는지를 보여준다. 위의 파일을 읽는 예제는 솔직히 조금 복잡하다. 이번의 예제는 한번의 함수 호출로 전체 파일을 읽는 readFile()
함수를 사용한다. readFile()
의 처음 두 인자는 파일 이름과 파일의 인코딩이다. Node.js 관례에 따라 마지막 인자는 콜백 함수이다. 콜백 함수의 인자로는 error
정보와 파일의 내용을 제공한다.
var fs = require("fs");
fs.readFile("foo.txt", "utf8", function(error, data) {
console.log(data);
});
다음 예제는 readFileSync()
를 사용해서 위와 동일한 작업을 동기적으로 수행한다. 동기화 코드는 조금 더 가독성이 있지만, 비동기화 코드와 같은 확장성을 제공하지 못한다.
var fs = require("fs");
var data = fs.readFileSync("foo.txt", "utf8");
console.log(data);
파일 시스템 모듈은 프로그램이 특정 파일들의 변경사항을 관찰할 수 있게 한다. 이것은 소스 코드가 수정되면 프로그램을 자동으로 재시작 시켜주는 nodemon과 같은 프로그램에게는 매우 유용하다. 다음 예제는 “foo.txt”
라는 파일을 관찰한다. 파일이 수정되면 콘솔에 이벤트에 대한 정보를 출력한다.
var fs = require("fs");
var fileName = "foo.txt";
fs.watch(fileName, {
persistent: true
}, function(event, filename) {
console.log(event + " event occurred on " + filename);
});
watch()
함수는 세개의 인자를 받는다. 첫번째 인자는 관찰하기 위한 파일의 이름이다. 두번째 인자는 선택사항으로 구성 설정을 제공하는데, 위 예제에서는 persistent
라는 이름의 불리언 값을 포함하는 객체이어야 한다. persistent
값이 true
이면 프로그램이 종료되지 않는다. 만약 두번째 인자가 생략된다면 기본으로 true
로 설정된다. 마지막 인자는 목표가 되는 파일이 수정될 때 트리거되는 콜백 함수이다. 콜백에는 이벤트 유형(change, rename 등)과 파일의 이름을 전달한다. watch()
가 기본 OS에 의존적이어서 모든 시스템에서 작동하지는 않을 수 있다는 것을 알고 있어야 한다. watch()
를 사용할 수 없다면 대신에 속도가 느린 watchFile()
을 사용할 수는 있다.
이 글은 파일 시스템 모듈에 대해 매우 높은 수준에서 소개했다. 그 모듈은 하나의 글에서 소개하기에는 너무 많은 약 50개가 넘는 함수를 포함하고 있다. 예를 들어 이글에서는 파일을 읽는 부분만을 다룰 뿐, 파일을 쓰는 부분에 대해서는 완전히 배제하였다. 더 깊이 이해하기 위해서는 모듈에 관한 문서를 찾아보기 바란다. 그리고, 동기화 함수는 아주아주 조심히 사용해야 한다는 것을 기억해라!